package com.xdxc.service.impl;


import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xdxc.emuns.QuestionType;
import com.xdxc.model.enums.AutoGradeQuestionType;
import com.xdxc.factory.GradingStrategyFactory;
import com.xdxc.feign.ExamFeign;
import com.xdxc.mapper.GradingResultMapper;
import com.xdxc.model.dto.CorrectAnswerDTO;
import com.xdxc.model.entity.GradingResult;
import com.xdxc.model.entity.ReviewTask;
import com.xdxc.model.entity.TempUserAnswer;
import com.xdxc.model.form.ScoringRequest;
import com.xdxc.response.Result;
import com.xdxc.service.serviceinterface.GradingResultService;
import com.xdxc.service.serviceinterface.ReviewTaskService;
import com.xdxc.service.strategy.gradingstrategy.GradingStrategy;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.util.*;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


@Slf4j
@Service
public class GradingResultServiceImpl extends ServiceImpl<GradingResultMapper, GradingResult> implements GradingResultService {

    private final GradingStrategyFactory strategyFactory;
    private final GradingResultMapper resultMapper;

    private final ExamFeign examFeign;

    private final RedisService redisService;
    private final ReviewTaskService reviewTaskService;


    private static final Set<String> AUTO_GRADE_TYPES = Arrays.stream(AutoGradeQuestionType.values())
            .map(Enum::name)
            .collect(Collectors.toSet());

    // 空答案标记对象
    private static final CorrectAnswerDTO NULL_ANSWER = new CorrectAnswerDTO();
    private static final int BATCH_SIZE = 100; // 可配置的批次大小
    private static final int MAX_RETRIES = 3; // 最大重试次数



    @Autowired
    public GradingResultServiceImpl(
            GradingStrategyFactory strategyFactory,
            RedisService redisService,
            GradingResultMapper resultMapper,
            ExamFeign examFeign,
            ReviewTaskService reviewTaskService
            ) {
            this.redisService= redisService;
            this.strategyFactory = strategyFactory;
            this.resultMapper = resultMapper;
            this.examFeign = examFeign;
            this.reviewTaskService=reviewTaskService;

    }



    @Transactional
    public void objectGrade(List<TempUserAnswer>  tempUserAnswerList,Long examId) {

        Map<Boolean, List<TempUserAnswer> > partitionedMap = tempUserAnswerList.stream()
                .collect(Collectors.partitioningBy(
                        ua -> ua.getAnswerType() != null && AUTO_GRADE_TYPES.contains(String.valueOf(ua.getAnswerType()))
                ));
        List<TempUserAnswer> autoGradeList = partitionedMap.get(true);
        List<TempUserAnswer> nonAutoGradeList = partitionedMap.get(false);


        //以问题问题类型分片
        Map<QuestionType, List<TempUserAnswer>> shards = shardByType(autoGradeList);
        // 使用线程安全的临时存储（键为批次索引，值为批次数据）
        ConcurrentHashMap<Integer, List<GradingResult>> batchMap = new ConcurrentHashMap<>();
        AtomicInteger batchCounter = new AtomicInteger(0);
        shards.entrySet().stream()
                .flatMap(entry -> {
                    AutoGradeQuestionType type = AutoGradeQuestionType.valueOf(String.valueOf(entry.getKey()));
                    List<TempUserAnswer> batch = entry.getValue();
                    GradingStrategy strategy = strategyFactory.getStrategy(type);
                    return batch.stream().map(ba -> {
                        try {
                            CorrectAnswerDTO correctAnswer = getCorrectAnswerWithRetry(examId , ba.getQuId(),ba.getCheckId());
                            return strategy.grade(ba, correctAnswer);
                        } catch (Exception e) {
                            return createDefaultGradingResult(new TempUserAnswer());// 创建默认评分结果
                        }
                    });
                })
                .forEach(result -> {
                    // 动态批处理逻辑
                    int currentBatchIndex = batchCounter.getAndUpdate(i ->
                            (i + 1) % BATCH_SIZE == 0 ? i + 1 : i
                    ) / BATCH_SIZE;

                    // 线程安全地添加到批处理Map
                    batchMap.compute(currentBatchIndex, (key, existingList) -> {
                        List<GradingResult> list = existingList != null ? existingList : new CopyOnWriteArrayList<>();
                        list.add(result);
                        return list;
                    });

                    // 检查并处理完整批次
                    if (batchMap.get(currentBatchIndex).size() >= BATCH_SIZE) {
                        List<GradingResult> fullBatch = batchMap.remove(currentBatchIndex);
                        saveBatch(fullBatch);
                    }
                });

        // 4. 处理剩余未满批次的数据
        batchMap.values().parallelStream()
                .filter(list -> !list.isEmpty())
                .forEach(this::saveBatch);
            // 5. 处理非自动评分的题目


            List<ReviewTask> reviewTaskList = nonAutoGradeList.stream()
                    .map(nonAutoGrade -> {
                        ReviewTask reviewTask = new ReviewTask();
                        reviewTask.setUserAnswerId(nonAutoGrade.getId());
                        reviewTask.setStatus(0);
                        return reviewTask;
                    })
                    .collect(Collectors.toList());
            reviewTaskService.saveBatch(reviewTaskList);


    }

    @Override
    public void subjectGradingResult(List<TempUserAnswer> tempUserAnswerList, Long examId) {

    }

    public Map<QuestionType, List<TempUserAnswer>> shardByType(List<TempUserAnswer> answers) {
        return answers.stream()
                .collect(Collectors.groupingByConcurrent(
                        answer -> QuestionType.valueOf(String.valueOf(answer.getAnswerType()))
                ));
    }


    private CorrectAnswerDTO getCorrectAnswerWithRetry(long examId, long questionId,long paperId) {
        String redisKey = "grading:" + examId;
        String fieldKey = String.valueOf(questionId);
        int retryCount = 0;

        while (retryCount < MAX_RETRIES) {
            try {
                // 1. 尝试从Redis获取
                CorrectAnswerDTO cachedAnswer = (CorrectAnswerDTO) redisService.getField(redisKey, fieldKey);
                if (cachedAnswer != null) {
                    if (cachedAnswer == NULL_ANSWER) {
                        throw new NoSuchElementException("No answer found for question: " + questionId);
                    }
                    return cachedAnswer;
                }

                // 2. 从服务获取
                Result<CorrectAnswerDTO> result = examFeign.getCorrectAnswer(paperId,questionId);

                if (result.getCode() == 1 && result.getData() != null) {
                    // 成功获取到答案，存入缓存
                    CorrectAnswerDTO correctAnswerDTO= result.getData();
                    log.info("result.getData()", result.getData());
                    redisService.updateField(redisKey, fieldKey, correctAnswerDTO);
                    redisService.expire(redisKey,10,TimeUnit.DAYS);
                    return result.getData();
                } else if (result.getCode() == 404) {
                    // 缓存空结果
                    redisService.updateField(redisKey, fieldKey, NULL_ANSWER);
                    redisService.expire(redisKey,10, TimeUnit.DAYS);
                    throw new NoSuchElementException("No answer found for question: " + questionId);
                }

                // 3. 尝试设置并重新获取
//                QuestionFeign.setCorrectAnswer(examId, questionId);
            } catch (FeignException e) {
                log.warn("Feign call failed for question {}, retry {}", questionId, retryCount + 1, e);


            }

            retryCount++;
            if (retryCount < MAX_RETRIES) {
                try {
                    Thread.sleep(100 * retryCount); // 指数退避
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("Interrupted while retrying", ie);
                }
            }
        }
        throw new RuntimeException("Failed to get correct answer after " + MAX_RETRIES + " attempts for question: " + questionId);
    }

    /**
     * 创建默认评分结果
     */
    private GradingResult createDefaultGradingResult(TempUserAnswer answer) {
        // 根据业务需求实现默认评分逻辑
        return new GradingResult(/* 默认值 */);
    }

    @Override
    public void subjectGradingResult(TempUserAnswer tempUserAnswer, Long examId) {



    }
}
